package com.wjr.mvc;

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @Author: wjr
 * @Description: 该类是一个映射器，任务是建立请求地址与方法的映射关系
 * @Date Created in  2020-09-09 15:49
 * @Modified By:
 */
public class HandlerMapping {
    private static Map<String,MVCMapping> date = new HashMap<>();

    /**
      * @Description 获取存在date里的对象信息
      * @param uri
      * @Return com.wjr.mvc.HandlerMapping.MVCMapping
      * @Author wjr
      * @Date Created in 2020/9/9 16:21
      */
    public static MVCMapping get(String uri){
        return date.get(uri);
    }
    /**
      * @Description 用于加载配置文件的对象信息
      * @param inputStream  读取配置文件的输入流
      * @Return void
      * @Author wjr
      * @Date Created in 2020/9/9 16:20
      */
    public static void loadInputStream(InputStream inputStream){
        Properties properties = new Properties();
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }

        //获取配置文件中描述的类
        Collection<Object> values = properties.values();
        for (Object cla:values){
            String className = (String) cla;
            try {
                //加载配置文件中的类
                Class c = Class.forName(className);
                //创建该类的对象
                Object obj = c.getConstructor().newInstance();

                //获取该类的所有方法
                Method[] methods = c.getMethods();
                for (Method m:methods){
                    //遍历方法集获取注解
                    Annotation[] annotations = m.getAnnotations();
                    if (annotations != null){
                        for (Annotation annotation: annotations){
                            if (annotation instanceof ResponseBody){
                                //该注解返回String类型给请求者
                                MVCMapping mvcMapping = new MVCMapping(obj, m, ResponseType.TEXT);
                                Object o = date.put(((ResponseBody)annotation).value(),mvcMapping);
                                if (o != null){
                                    //说明请求地址已存在
                                    throw new RuntimeException("请求地址重复："+((ResponseBody)annotation).value());
                                }
                            }else if (annotation instanceof ResponseView){
                                //该注解返回页面给请求者
                                MVCMapping mvcMapping = new MVCMapping(obj, m, ResponseType.VIEW);
                                Object o = date.put(((ResponseView)annotation).value(),mvcMapping);
                                if (o != null){
                                    //说明请求地址已存在
                                    throw new RuntimeException("请求地址重复："+((ResponseView)annotation).value());
                                }
                            }
                        }
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**
      * @Description 映射器数据结构
      * @param
      * @Return
      * @Author wjr
      * @Date Created in 2020/9/9 15:52
      */
    public static class MVCMapping{
        private Object obj;
        private Method method;
        private ResponseType type;

        public MVCMapping() {
        }

        public MVCMapping(Object obj, Method method, ResponseType type) {
            this.obj = obj;
            this.method = method;
            this.type = type;
        }

        public Object getObj() {
            return obj;
        }

        public void setObj(Object obj) {
            this.obj = obj;
        }

        public Method getMethod() {
            return method;
        }

        public void setMethod(Method method) {
            this.method = method;
        }

        public ResponseType getType() {
            return type;
        }

        public void setType(ResponseType type) {
            this.type = type;
        }
    }
}
